package ha.web.server.manager;

import ha.web.server.database.UserId;
import ha.web.server.database.UserManager;
import ha.web.server.database.UserStatistics;
import ha.web.server.exceptions.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class GameMangerServerSide {
	
	private UserManager userManager = UserManager.getInstance();
	
	private static GameMangerServerSide singleton = null;
	//Waiting user at waiting page (by userId)
	private List<UserId> waitingList; 
	//connect between userId to game (key=userId  value=gameId) 
	private HashMap<Integer, Integer> gamePlaying;
	//connect between gameId to GameRunning object (key=gameId  value=GameRunning) 
	private HashMap<Integer, GameRunning> games;
	//connect between userId to UserID object (key=UserId  value=UserId)
	private Map<Integer,UserId> players;
	
	public List<UserId> getWaitingList(){
		return  waitingList;
	}
	public Set<Integer> getGamesId(){ 
		return games.keySet();
	}
	public  GameRunning getGameById(int gameId)
	{
		return games.get(gameId);
	}
	/*
	public String[] GetCurrentGames(){
		
		..String[] gamesInfo;
		Integer[] temp =(Integer[]) games.keySet().toArray();
		for 
		return 
	}
	*/
	private GameMangerServerSide() {	
		games = new HashMap<Integer, GameRunning>();
		waitingList = new ArrayList<UserId>();
		gamePlaying = new HashMap<Integer, Integer>();
		players = new HashMap<Integer, UserId>();
	}
	
	public static GameMangerServerSide getInstance() {
		if(singleton==null)
			singleton = new GameMangerServerSide();
		return singleton;
	}
	
	public List<Integer> getPlayersIdOfGame(int gameId) {
		return games.get(new Integer(gameId)).getPlayers();
	}
	
	public List<String> getPlayersNickNameOfGame(int gameId) {
		List<Integer> tmp = getPlayersIdOfGame(gameId);
		ArrayList<String> toRet =  new ArrayList<String>();
		toRet.add(players.get(tmp.get(0)).getNickName());
		toRet.add(players.get(tmp.get(1)).getNickName());
		return toRet;
	}
	
	public UserId getPlayerById(int userId) throws UserNotFoundException {
		if(!players.containsKey(userId))
			throw new UserNotFoundException("user not found");
		return players.get(userId);
	}
	
	public boolean isUserAdmin(int userId) 
	{
			UserId user;
			try {
				user = getPlayerById(userId);
			} catch (UserNotFoundException e) {
				// TODO Auto-generated catch block
				return false;
			}
			return user.isUserAdmin();
	}
	public boolean isUserLogedin(int userId)
	{
		if (this.getGameById(userId) != null)
			return true;
		for(int i=0; i<this.waitingList.size();i++){	
			if (this.waitingList.get(i).getUserID() == userId){
				return true;
			}
		}
		return false;
	}
	public String getNickNameById(int userId) throws UserNotFoundException {
		return getPlayerById(userId).getNickName();
	}
	
	public String getOtherPlayerNickName(int userId) {
		return games.get(gamePlaying.get(userId)).getOtherPlayer(userId).getNickName();
	}
	
	public String resignedGame(int userId) throws UserNotFoundException  {
		int gameId = getGameIdByUserId(userId);
		GameRunning game = games.get(gameId);
		List<UserStatistics> tmp = game.endGame(userId,false,true);
		userManager.updateStatistics(tmp);
		return game.getGameHistory(userId);
	}
	
	public int getGameIdByUserId(int userId) throws UserNotFoundException {
		if (gamePlaying.containsKey(userId)) 
			return gamePlaying.get(userId);			
		throw new UserNotFoundException("Error: player not in any game");
	}
	
	public boolean isMyTurn(int userId) {
		Integer gameId = gamePlaying.get(userId);
		//check not in waiting list:
		if (waitingList.contains(userId))
			return false;
		//check player turn:
		return games.get(gameId).itIsTurn(userId);
	}
	
	public String getPlayerTurnByGameId(int gameId) {
		return games.get(new Integer(gameId)).getPlayerNameTurn();
	}
	
	
	public void switchTurn(int gameId) {
		games.get(gameId).switchTurn();	
	}

	public int playerLogin(String userName, String userPass) throws UserNotFoundException, RegisterException, LoginException  {
		UserId p = UserManager.getInstance().login(userName, userPass);
		//administrator can only watch current games, can't play a game
		if (this.isUserAdmin(p.getUserID())){ 
			return p.getUserID();
		}
		//if person already logedin  - need ot finish game
		if (this.isUserLogedin(p.getUserID())){
			return p.getUserID();
		}
		if (waitingList.size() > 0){
			UserId other = waitingList.remove(0);
			GameRunning newGame = new GameRunning(other,p);
			games.put(newGame.getGameId(), newGame);
			gamePlaying.put(p.getUserID(),newGame.getGameId());
			gamePlaying.put(other.getUserID(),newGame.getGameId());
		}else // add player and return
			waitingList.add(p);
		players.put(p.getUserID(), p);
		return p.getUserID();
	}

	public void addLineToChat(int player, String line) throws UserNotFoundException  {
		int gameId = getGameIdByUserId(player);
		games.get(gameId).addLineToChat(player, line);
		
	}
	
	public String getChat(int player) throws UserNotFoundException  {
		int gameId = getGameIdByUserId(player);
		return games.get(gameId).getChat();
	}
	
	public String setLastMove(int userId,String lastMove) throws UserNotFoundException, NotYourTurnException, EmptyMoveException, SyntaxMoveNotValidException, MoveNotValidException, MoveOutOfBoundException  {
		int gameId = getGameIdByUserId(userId);
		List<UserStatistics> ans =  games.get(gameId).setLastMove(userId, lastMove);
		if(ans!=null) {
			updateStatistics(ans); 
			return endGame(userId,false);
		}
		return "";
	}
	
	public String getLastMove(int user) throws UserNotFoundException  {
		int gameId = getGameIdByUserId(user);
		return games.get(gameId).getLastMove(user);
	}
	
	public String getPrevTable(int user) throws UserNotFoundException {
		int gameId = getGameIdByUserId(user);
		return games.get(gameId).getTable();
	}
	
	public String getTable(int user) throws UserNotFoundException {
		int gameId = getGameIdByUserId(user);
		return games.get(gameId).getTable();
	}

	public void registerNewUser(String userName, String userPass,String rePass,String nickName, boolean admin) throws LoginException, RegisterException {
		UserManager.getInstance().createNewUserAtDB(userName, userPass, rePass, nickName, admin);
	}

	public String isGameEnded(int userId) throws UserNotFoundException  {
		int gameId = getGameIdByUserId(userId);
		GameRunning game = games.get(gameId);
		if(games.get(gameId).gameEnded()) {
			return endGame(userId,true);
		}
		return "";
	}
	
	public void updateStatistics(List<UserStatistics> statistics) {
		userManager.updateStatistics(statistics);
	}
	
	public String getComm() {
		return "This cookie does not collect information, mainly because we do not have the"+
				" slightest interest in knowing you any details, because if you thought for a moment,"+
				" you are welcome to contact the UN High Commissioner complaints. This cookie is stored"+
				" identifying information that need this game, this cookie maliciously destroyed when you"+
				" close the browser";
	}

	public String getUserStatistics(String nickName, int userId) throws LoginException {
		return userManager.getUserStatistics(nickName,userId);
		
	}

	public boolean isUserAtDB(String nickName, int userId) throws LoginException {
		return userManager.isUserAtDB(nickName,userId);
	}
	
	public String endGame(int userId, boolean myTurnChk) throws UserNotFoundException {
		int gameId = getGameIdByUserId(userId);
		GameRunning game = games.get(gameId);
		if(!myTurnChk) {
			List<UserStatistics> tmp = game.endGame(userId,false,true);
			userManager.updateStatistics(tmp);
		} else
			game.setGameEndedForPlayer(userId);
		String his = game.getGameHistory(userId);
		String table = getTable(userId);
		String prvTable = getPrevTable(userId);
		String lastMove = getLastMove(userId);
		if(game.isGameEndedForBoth()) {
			List<Integer> gamePlayers = getPlayersIdOfGame(gameId);
			games.remove(gameId); 
			players.remove(gamePlayers.get(0));
			players.remove(gamePlayers.get(1));
			gamePlaying.remove(gamePlayers.get(0));
			gamePlaying.remove(gamePlayers.get(1));
		}
		if(myTurnChk)
			return prvTable+"$"+lastMove+"$"+table+"$"+his;
		else
			return table+"$"+his+"$"+lastMove;
	}
	public String getStatistics(int userId) throws UserNotFoundException {
		int gameId = getGameIdByUserId(userId);
		return games.get(gameId).getStatistics(userId);
	}
}
